<?php
namespace App\Http\Controllers\Api\Traits;
use App\Jobs\System\CheckBatchCahceDataLossJob;
use App\Models\Shop\WxShopOrder;
use App\Models\User\WxUser;
use App\Models\User\WxUserWithdrawal;
use App\Models\WxOrder;
use App\Wen\Utils\Settings;
use App\Wen\Utils\UserUtils;
use Yansongda\Pay\Pay;
use App\Wen\Utils\Utils;
use App\Lib\Pay\EPay;
use Illuminate\Support\Facades\Cache;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use Yansongda\Pay\Plugin\Wechat\Fund\Transfer\QueryBatchIdPlugin;

trait PayTrait{

    public function transferBatchQuery($provider, $batch_id, $need_query_detail = false){
        if($provider == 'wxpay'){
            $config = json_decode(Cache::get('app_pay_config'), true);
            if(_empty_($config)){
                CheckBatchCahceDataLossJob::dispatch();
            }
            $pay = Pay::wechat($config);
            $plugins = $pay->mergeCommonPlugins([QueryBatchIdPlugin::class]);
            // need_query_detail:【是否查询转账明细单】 true-是；false-否，默认否。商户可选择是否查询指定状态的转账明细单，当转账批次单状态为“FINISHED”（已完成）时，才会返回满足条件的转账明细单
            $result = $pay->pay($plugins ,['batch_id' => $batch_id, 'need_query_detail' => true, 'detail_status' => 'ALL']);
            $result_arr = $result->toArray();
            if(!_empty_(_array_key($result_arr, 'transfer_batch', ''))){
                // 查询成功
                return $result_arr;
            }else{
                if(_array_key($result_arr, 'code', '') == 'NOT_FOUND'){
                    WxUserWithdrawal::whereIn('wx_batch_id', $batch_id)->where('state', 3)->update([
                        'state' => 2,
                        'refuse_tip' => '查询的转账批次单不存在',
                    ]);
                }else{
                    _logger_(__file__, __line__, '微信商家转账到零钱-查询批次单失败-批次号'.$batch_id.'-：'.json_encode($result_arr, JSON_UNESCAPED_UNICODE));
                    UserUtils::assistant_notice('admin', '微信商家转账到零钱失败-查询批次单失败-批次号'.$batch_id.'-：'.json_encode($result_arr, JSON_UNESCAPED_UNICODE));
                }
                return null;
            }
        }else{
            throw new \Exception('暂时未实现');
        }
    }

    /**
     * @param $provider
     * @param $pay_type
     * @param $list
     * 'transfer_detail_list' => [
    [
    'out_detail_no' => (string)(time() + 5),  // 商家明细单号
    'transfer_amount' => 0.1 * 100,  // 转账金额
    'transfer_remark' => '商家付款到零钱',  // 单条转账备注（微信用户会收到该备注）
    'openid' => 'ozxxxxxxxxxx', //  转账用户的 openid
    ],
    ],
     * @param $batch_name 余额提现
     * @param $batch_remark 平台转账到用户微信零钱
     * @throws \Exception
     */
    public function transferBatch($provider, $pay_type, $list, $batch_name = '余额提现', $batch_remark = '平台转账到用户微信零钱'){
        $total_amount = 0;
        if(!_empty_($list)){
            foreach ($list as $item){
                $total_amount += $item['transfer_amount'];
            }
        }
        if($provider == 'wxpay'){
            $config = json_decode(Cache::get('app_pay_config'), true);
            if(_empty_($config)){
                CheckBatchCahceDataLossJob::dispatch();
            }
            if($pay_type == 'app'){
                $appid = Settings::get('app_app_id', '');
            }else if($pay_type == 'mp'){
                $appid = Settings::get('mp_app_id', '');
            }else if($pay_type == 'mini'){
                $appid = Settings::get('app_id', '');
            }else{
                $appid = Settings::get('app_id', '');
            }
            $result = Pay::wechat($config)->transfer([
                'appid' => $appid, // 微信小程序的app_id
                'out_batch_no' => (string)time(), // 商家批次单号
                'batch_name' => $batch_name,    // 该笔批量转账的名称
                'batch_remark' => $batch_remark,  // 转账说明
                'total_amount' => (int)$total_amount,  // 转账金额，单位：分
                'total_num' => count($list),   // 转账总笔数
                'transfer_detail_list' => $list,
            ]);
            $result_arr = $result->toArray();
            if(!_empty_(_array_key($result_arr, 'batch_id', ''))){
                // 转账成功
                return _array_key($result_arr, 'batch_id', '');
            }else{
                if(_array_key($result_arr, 'code', '') == 'NOT_ENOUGH'){
                    throw new \Exception('资金不足');
                }
                _logger_(__file__, __line__, '微信商家转账到零钱(总'. ($total_amount/100) .'元)失败：'.json_encode($result_arr, JSON_UNESCAPED_UNICODE));
                UserUtils::assistant_notice('admin', '微信商家转账到零钱(总'. ($total_amount/100) .'元)失败：'.json_encode($result_arr, JSON_UNESCAPED_UNICODE));
                return null;
            }
        }else if($provider == 'alipay'){
            throw new \Exception('暂时未实现');
            $config = json_decode(Cache::get('app_pay_config'), true);
            if(_empty_($config)){
                CheckBatchCahceDataLossJob::dispatch();
            }
            if($pay_type == 'app'){

            }else if($pay_type == 'mp'){

            }else if($pay_type == 'mini'){

            }
            $order = [
                'out_biz_no' => time(),
                'trans_amount' => 0.1,
                'product_code' => 'TRANS_ACCOUNT_NO_PWD',
                'payee_info' => [
                    'identity' => 'ghdhjw7124@sandbox.com',
                    'name' => '张三',
                    'identity_type' => 'ALIPAY_LOGON_ID',
                ],
                'remark'=>'赔付金'//相当于转账里面的备注
            ];
            $result = Pay::alipay($config)->transfer($order);
        }
    }

    /**
     * @param $uid
     * @param $provider
     * @param $pay_type
     * @param $total_fee
     * @param $body
     * @param $out_trade_no
     * @param int $order_type 1: 普通订单 2：商城订单
     * @return \Illuminate\Http\JsonResponse
     */
    public function payHandler($uid, $provider, $pay_type, $total_fee, $body, $out_trade_no, $order_type = 1){
        global $__MINI_GLOBAL_DEVICE__;
        if($__MINI_GLOBAL_DEVICE__ == 'h5'){
            if($provider == 'wxpay'){
                if($pay_type != 'mp' && $pay_type != 'h5'){
                    $pay_type = 'h5';
                }
            }else{
                $pay_type = 'h5';
            }
        }
        if($provider == 'wxpay'){
            $config = json_decode(Cache::get('app_pay_config'), true);
            if(_empty_($config)){
                CheckBatchCahceDataLossJob::dispatch();
            }
            if($order_type == 1){
                $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'wx_order_');
            }else{
                $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'wx_shoporder_');
            }

            $config['wechat']['default']['return_url'] = route('pay.return', ['out_trade_no'=>$outTradeNoPre]);
            // 微信支付
            if($pay_type == 'app'){
//                $openid = WxUser::where('id', $uid)->value('weixin_app_openid');
                // 支付
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'description' => $body,
                    'amount' => [
                        'total' => $total_fee * 100,
                    ],
                ];
                $pay_data = Pay::wechat($config)->app($order);
                $pay_data['query_state_no'] = $outTradeNoPre;
                if($order_type == 1){
                    WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'app', 'order_serial_platform'=>0]);
                }else{
                    WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'app', 'serial_platform'=>0]);
                }
                return $this->success($pay_data);

            }else if($pay_type == 'h5'){
                global $__MINI_GLOBAL_IP__;
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'description' => $body,
                    'amount' => [
                        'total' => $total_fee * 100,
                    ],
                    'scene_info' => [
                        'payer_client_ip' => $__MINI_GLOBAL_IP__,
                        'h5_info' => [
                            'type' => 'Wap',
                        ]
                    ],
                ];

                $pay_data = Pay::wechat($config)->wap($order);
                $h5_url = $pay_data->h5_url;
                $cache_html = '<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="refresh" content="0;url='.$h5_url.'"> <title>Redirecting</title> </head> <body></body> </html>';
                $r = Cache::put($outTradeNoPre, $cache_html, $seconds = 300);
                if($r){
                    if($order_type == 1){
                        WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'h5', 'order_serial_platform'=>0]);
                    }else{
                        WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'h5', 'serial_platform'=>0]);
                    }
                    return $this->success(['direct'=>route('pay.direct', ['out_trade_no'=>$outTradeNoPre]), 'query_state_no'=>$outTradeNoPre]);
                }else{
                    return $this->fail(200005, ['msg'=>'系统写入缓存时失败，请联系管理员']);
                }
            }else if($pay_type == 'yi') {
                $epay_config = json_decode(Cache::get('yi_pay_config'), true);
                if(_empty_($epay_config)){
                    CheckBatchCahceDataLossJob::dispatch();
                }

                if($order_type == 1){
                    $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'yi_order_');
                }else{
                    $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'yi_shoporder_');
                }

                $return_url = route('pay.return', ['out_trade_no' => $outTradeNoPre]);
                $epay = new EPay();
                $epay->key($epay_config['app_secret']);

                // 发起订单
                try {
                    $pay_data = $epay->pid($epay_config['app_id'])
                        ->url($epay_config['provider_url'])
                        ->outTradeNo($out_trade_no)
                        ->type('wxpay')
                        ->notifyUrl($epay_config['notify_url'])
                        ->returnUrl($return_url)
                        ->money($total_fee)
                        ->name($body)
                        ->sitename($epay_config['site'])
                        ->submit()
                        ->getHtmlForm();
                    $r = Cache::put($outTradeNoPre, Utils::payDirectHtmlForApp('', $pay_data), $seconds = 300);
                    if ($r) {
                        if($order_type == 1){
                            WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'yi', 'order_serial_platform'=>0]);
                        }else{
                            WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'yi', 'serial_platform'=>0]);
                        }
                        return $this->success(['direct' => route('pay.direct', ['out_trade_no' => $outTradeNoPre]), 'query_state_no' => $outTradeNoPre]);
                    } else {
                        return $this->fail(200005, ['msg' => '系统写入缓存时失败，请联系管理员']);
                    }
                } catch (\Exception $e) {
                    _logger_(__file__, __line__, $e->getMessage());
                    return $this->fail(200006, ['msg' => '易支付生成订单出错']);
                }
            }else if($pay_type == 'code' || $pay_type == 'code_pc') {
                // native支付
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'description' => $body,
                    'amount' => [
                        'total' => $total_fee * 100,
                    ],
                ];
                $pay_data = Pay::wechat($config)->scan($order);
                if($pay_data && $pay_data->code_url){
                    if($order_type == 1){
                        WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>$pay_type, 'order_serial_platform'=>0]);
                    }else{
                        WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>$pay_type, 'serial_platform'=>0]);
                    }
                    return $this->success(['url'=>$pay_data->code_url, 'code'=>QrCode::size(300)->generate($pay_data->code_url), 'query_state_no'=>$outTradeNoPre]);
                }
                return $this->fail(200006, $pay_data);
            }else if($pay_type == 'mp') {
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'description' => $body,
                    'amount' => [
                        'total' => $total_fee * 100,
                    ],
                    'payer' => [
                        'openid' => WxUser::where('id', $uid)->value('weixin_mp_openid'),
                    ],
                ];
                _logger_(__file__, __line__, '111111111111111111');
                try {
                    $result = Pay::wechat($config)->mp($order);
                    if($result && $result->paySign){
                        if($order_type == 1){
                            WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'mp', 'order_serial_platform'=>0]);
                        }else{
                            WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'mp', 'serial_platform'=>0]);
                        }
                        // todo优化: 返回二维码，以及url 微信文档：https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/jsapi-transfer-payment.html
                        _logger_(__file__, __line__, $result->toArray());
                        return $this->success([
                            'appId' => $result->appId,
                            'timeStamp' => $result->timeStamp,
                            'nonceStr' => $result->nonceStr,
                            'package' => $result->package,
                            'signType' => $result->signType,
                            'paySign' => $result->paySign,
                            'prepayid' => $result->prepayid,
                            'query_state_no' => $outTradeNoPre
                        ]);
                    }
                }catch (\Exception $e){
                    _logger_(__file__, __line__, $e->getMessage());
                    return $this->fail(200006);
                }
            }else if($pay_type == 'mini') {
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'description' => $body,
                    'amount' => [
                        'total' => $total_fee * 100,
                        'currency' => 'CNY',
                    ],
                    'payer' => [
                        'openid' => WxUser::where('id', $uid)->value('weixin_openid'),
                    ],
                ];
                try {
                    $result = Pay::wechat($config)->mini($order);
                    if($result && $result->paySign){
                        if($order_type == 1){
                            WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'mini', 'order_serial_platform'=>0]);
                        }else{
                            WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'mini', 'serial_platform'=>0]);
                        }
                        // todo优化: 返回二维码，以及url 微信文档：https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/jsapi-transfer-payment.html
                        return $this->success([
                            'appId' => $result->appId,
                            'timeStamp' => $result->timeStamp,
                            'nonceStr' => $result->nonceStr,
                            'package' => $result->package,
                            'signType' => $result->signType,
                            'paySign' => $result->paySign,
                            'query_state_no' => $outTradeNoPre
                        ]);
                    }
                }catch (\Exception $e){
                    _logger_(__file__, __line__, $e->getMessage());
                    return $this->fail(200006);
                }
            }
        }else if($provider == 'alipay'){
            $config = json_decode(Cache::get('app_pay_config'), true);
            if(_empty_($config)){
                CheckBatchCahceDataLossJob::dispatch();
            }
            if($order_type == 1){
                $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'ali_order_');
            }else{
                $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'ali_shoporder_');
            }


            $config['alipay']['default']['return_url'] = route('pay.return', ['out_trade_no'=>$outTradeNoPre]);
            $config['alipay']['default']['notify_url'] = env('APP_URL'). '/api/v1/app/ali/notify/app';

            // 支付宝支付
            if($pay_type == 'app'){

                $order = [
                    'out_trade_no' => $out_trade_no,
                    'total_amount' => $total_fee,
                    'subject'      => $body,
                ];
                if($order_type == 1){
                    WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'app', 'order_serial_platform'=>1]);
                }else{
                    WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'app', 'serial_platform'=>1]);
                }
                return Pay::alipay($config)->app($order);
//                $pay_data->query_state_no = $outTradeNoPre;
            }else if($pay_type == 'h5'){
                $config['alipay']['default']['notify_url'] = env('APP_URL'). '/api/v1/app/ali/notify/wap';
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'total_amount' => $total_fee,
                    'subject' => $body,
                    'quit_url' => env('APP_URL'),
                ];

                $pay_data = Pay::alipay($config)->wap($order);
                $pay_data = $pay_data->getBody();
                $r = Cache::put($outTradeNoPre, Utils::payDirectHtmlForApp('', $pay_data), $seconds = 300);
                if($r){
                    if($order_type == 1){
                        WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'h5', 'order_serial_platform'=>1]);
                    }else{
                        WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'h5', 'serial_platform'=>1]);
                    }
                    return $this->success(['direct'=>route('pay.direct', ['out_trade_no'=>$outTradeNoPre]), 'query_state_no'=>$outTradeNoPre]);
                }else{
                    return $this->fail(200005, ['msg'=>'系统写入缓存时失败，请联系管理员']);
                }
            }else if($pay_type == 'yi') {
                $epay_config = json_decode(Cache::get('yi_pay_config'), true);
                if(_empty_($epay_config)){
                    CheckBatchCahceDataLossJob::dispatch();
                }

                if($order_type == 1){
                    $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'yi_order_');
                }else{
                    $outTradeNoPre = Utils::outTradeNoPre($out_trade_no, 'yi_shoporder_');
                }

                $return_url = route('pay.return', ['out_trade_no' => $outTradeNoPre]);
                $epay = new EPay();
                $epay->key($epay_config['app_secret']);

                // 发起订单
                try {
                    $pay_data = $epay->pid($epay_config['app_id'])
                        ->url($epay_config['provider_url'])
                        ->outTradeNo($out_trade_no)
                        ->type('alipay')
                        ->notifyUrl($epay_config['notify_url'])
                        ->returnUrl($return_url)
                        ->money($total_fee)
                        ->name($body)
                        ->sitename($epay_config['site'])
                        ->submit()
                        ->getHtmlForm();
                    $r = Cache::put($outTradeNoPre, Utils::payDirectHtmlForApp('', $pay_data), $seconds = 300);
                    if ($r) {
                        if($order_type == 1){
                            WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>'yi', 'order_serial_platform'=>1]);
                        }else{
                            WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>'yi', 'serial_platform'=>1]);
                        }
                        return $this->success(['direct' => route('pay.direct', ['out_trade_no' => $outTradeNoPre]), 'query_state_no' => $outTradeNoPre]);
                    } else {
                        return $this->fail(200005, ['msg' => '系统写入缓存时失败，请联系管理员']);
                    }
                } catch (\Exception $e) {
                    _logger_(__file__, __line__, $e->getMessage());
                    return $this->fail(200006, ['msg' => '易支付生成订单出错']);
                }
            }else if($pay_type == 'code' || $pay_type == 'code_pc') {
                $order = [
                    'out_trade_no' => $out_trade_no,
                    'total_amount' => $total_fee,
                    'subject'      => $body,
                ];
                $pay_data = Pay::alipay($config)->scan($order);
                if($pay_data && $pay_data->code_url){
                    if($order_type == 1){
                        WxOrder::where('order_number', $out_trade_no)->update(['order_serial_platform_type'=>$pay_type, 'order_serial_platform'=>1]);
                    }else{
                        WxShopOrder::where('order_id', $out_trade_no)->update(['serial_platform_type'=>$pay_type, 'serial_platform'=>1]);
                    }
                    return $this->success(['url'=>$pay_data->code_url, 'code'=>QrCode::size(300)->generate($pay_data->code_url), 'query_state_no'=>$outTradeNoPre]);
                }
                return $this->fail(200006, $pay_data);
            }
        }
    }
}
